package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.apis.article.IArticleClient;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.tess4j.Tess4jClient;
import com.heima.file.service.FileStorageService;
import com.heima.model.common.apArticle.dato.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.wemedia.pojos.WmChannel;
import com.heima.model.common.wemedia.pojos.WmNews;
import com.heima.model.common.wemedia.pojos.WmSensitive;
import com.heima.model.common.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {

    @Autowired
    private WmNewsMapper wmNewsMapper;

    @Autowired(required = false)
    private GreenTextScan greenTextScan;

    @Autowired(required = false)
    private IArticleClient articleClient;

    @Autowired
    private WmChannelMapper wmChannelMapper;

    @Autowired(required = false)
    private WmUserMapper wmUserMapper;

    @Autowired
    private FileStorageService fileStorageService;

    @Autowired(required = false)
    private GreenImageScan greenImageScan;

    @Autowired(required = false)
    private IArticleClient articleClientFeign;

    @Autowired
    private WmSensitiveMapper wmSensitiveMapper;

    @Autowired
    private Tess4jClient tess4jClient; //图片文字审核

        /**
         * 自动审核文章-主方法
         *
         * @param newsId
         */
        @Override
        @Async//执行异步线程
        public void autoScanWmNews(Integer newsId) {
            //1.查询自媒体文章
            WmNews wmNews = wmNewsMapper.selectById(newsId);
            //如果自媒体文章不存在，则直接终止
            if (wmNews == null) {
                throw new RuntimeException("WmNewsAutoScanServiceImpl-文章不存在");
            }

            //1.5 对wmnews中抽取文本和图片
            Map<String, Object> imageAndTextMap = chouquImageAndTextFromWmNews(wmNews);

            //1.6自管理敏感词审核
            Boolean sensitiveScanFlag = handleSensitiveScan(wmNews, (String) imageAndTextMap.get("content"));
            if (!sensitiveScanFlag) {
                return;
            }

            //2.审核文本
            Boolean textFlag = handleTextScan(wmNews, (String) imageAndTextMap.get("content"));
            if (!textFlag) {
                return;
            }

            //3.审核图片
            Boolean imageFlag = handleImageScan(wmNews, (List<String>) imageAndTextMap.get("imageUrlList"));
            if (!imageFlag) {
                return;
            }
            //4.调用feign接口保存三剑客
            Long articleId = saveAppArticle(wmNews);

            //5.修改wm_news表状态
            wmNews.setArticleId(articleId);
            updateWmNews(wmNews, WmNews.Status.PUBLISHED.getCode(), "发布审核成功");
        }

        /**
         * 抽取的第五个方法，自管理敏感词过滤
         *
         * @param wmNews
         * @param content 文章内容 文本
         * @return
         */
        private Boolean handleSensitiveScan(WmNews wmNews, String content) {
            Boolean flag = true;

            //1.查询敏感词库的集合
            List<WmSensitive> wmSensitives = wmSensitiveMapper.selectList(null);
            List<String> sensitiveList = wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());

            //2.执行DFA初始化敏感词库
            SensitiveWordUtil.initMap(sensitiveList);

            //3.进行匹配，查看是否有命中
            Map<String, Integer> resultMap = SensitiveWordUtil.matchWords(content);

            if (resultMap.size() > 0) {//命中，表示审核失败
                updateWmNews(wmNews, WmNews.Status.FAIL.getCode(), "当前文本中包含自管理敏感词库信息");
                flag = false;
            }
            return flag;
        }

        /**
         * 抽取的第四个方法，保存三剑客
         *
         * @param wmNews
         */
        private Long saveAppArticle(WmNews wmNews) {
            ArticleDto dto = new ArticleDto();
            BeanUtils.copyProperties(wmNews, dto);
            //布局
            dto.setLayout(wmNews.getType());
            //作者名称
            dto.setAuthorId(Long.valueOf(wmNews.getUserId()));
            WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());
            dto.setAuthorName(wmUser.getName());

            //频道名称
            WmChannel wmChannel = wmChannelMapper.selectById(dto.getChannelId());
            dto.setChannelName(wmChannel.getName());

            //点赞，收藏，阅读，评论数量
            dto.setLikes(0);
            dto.setViews(0);
            dto.setCollection(0);
            dto.setComment(0);

            //时间
            dto.setCreatedTime(new Date());

            //远程保存feign接口
            ResponseResult result = articleClientFeign.saveArticle(dto);
            if (result.getCode() != 200) {
                return null;
            }
            return (Long) result.getData();
        }

        /**
         * 抽取的第三个方法，审核图片
         *
         * @param wmNews
         * @param imageUrlList 图片地址的集合
         * @return
         */
        private Boolean handleImageScan(WmNews wmNews, List<String> imageUrlList) {
            Boolean flag = true;
            try {
                List<byte[]> imageByteList = new ArrayList<>();
                //下载图片
                if (imageUrlList != null && imageUrlList.size() > 0) {
                    for (String imageUrl : imageUrlList) {
                        //下载图片
                        byte[] bytes = fileStorageService.downLoadFile(imageUrl);

                        //图片OCR审核
                        InputStream in = new ByteArrayInputStream(bytes);
                        BufferedImage image = ImageIO.read(in);
                        String resultText = tess4jClient.doOCR(image);
                        //执行自管理敏感词审核
                        Boolean sensitiveScanFlag = handleSensitiveScan(wmNews, resultText);
                        if (!sensitiveScanFlag) {
                            return false;
                        }

                        imageByteList.add(bytes);
                    }
                }
                // //审核图片
                // Map map = greenImageScan.imageScan(imageByteList);
                // //违规
                // if (map.get("suggestion").equals("block")) {
                //     //修改wmnews表
                //     updateWmNews(wmNews, WmNews.Status.FAIL.getCode(), "当前图片中包含敏感信息");
                //     flag = false;
                // }
                // //人工
                // if (map.get("suggestion").equals("review")) {
                //     //修改wmnews表
                //     updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "当前图片中包含不确定的信息");
                //     flag = false;
                // }
            } catch (Exception e) {
                e.printStackTrace();
                flag = false;
            }
            return flag;
        }

        /**
         * 抽取的第二个方法，审核文本
         *
         * @param wmNews content 文本
         * @return
         */
        private Boolean handleTextScan(WmNews wmNews, String content) {
            Boolean flag = true;
            //调用审核文本的接口
            try {
                // Map map = greenTextScan.greeTextScan(content);
                // //违规
                // if (map.get("suggestion").equals("block")) {
                //     //修改wmnews表
                //     updateWmNews(wmNews, WmNews.Status.FAIL.getCode(), "当前文本中包含敏感词汇");
                //     flag = false;
                // }
                // //人工
                // if (map.get("suggestion").equals("review")) {
                //     //修改wmnews表
                //     updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "当前文本中包含不确定的词汇");
                //     flag = false;
                // }
            } catch (Exception e) {
                e.printStackTrace();
                flag = false;
            }
            return flag;
        }

        private int updateWmNews(WmNews wmNews, Short status, String message) {
            wmNews.setStatus(status);
            wmNews.setReason(message);
            return wmNewsMapper.updateById(wmNews);
        }

        /**
         * 抽取的第一个方法，抽取文本和图片
         *
         * @param wmNews
         * @return
         */
        private Map<String, Object> chouquImageAndTextFromWmNews(WmNews wmNews) {

            //定义一个字符串,用来保存文本
            StringBuilder sb = new StringBuilder();
            //定义一个list集合，用来保存图片地址
            List<String> imageUrlList = new ArrayList<>();

            //1.获取文本
            String content = wmNews.getContent();
            String title = wmNews.getTitle();
            String labels = wmNews.getLabels();
            sb.append(title);
            sb.append(labels);

            //1.5 从文章内容中抽取文本和图片
            List<Map> contentList = JSONArray.parseArray(content, Map.class);
            if (contentList != null && contentList.size() > 0) {
                for (Map map : contentList) {
                    //文本
                    if (map.get("type").equals("text")) {
                        String textValue = (String) map.get("value");
                        sb.append(textValue);
                    }
                    //图片
                    if (map.get("type").equals("image")) {
                        String imageValue = (String) map.get("value");
                        imageUrlList.add(imageValue);//['a.jpg','b.jpg']
                    }
                }
            }
            //2.获取封面图片
            String images = wmNews.getImages();//"aa.jpg,bb.jpg"
            //imageUrlList.add(images);//['a.jpg','b.jpg',"aa.jpg,bb.jpg"] 不可以
            String[] split = images.split(",");
            imageUrlList.addAll(Arrays.asList(split));


            //3.返回数据
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("content", sb.toString());
            resultMap.put("imageUrlList", imageUrlList);
            return resultMap;
        }



}